iT邦幫忙

2025 iThome 鐵人賽

DAY 20
0
Software Development

軟體開發養成計畫:以小程式實作深化開發能力系列 第 20

[ Day 20 ] 寫程式也能當鬧鐘?Python 記事提醒小實作

  • 分享至 

  • xImage
  •  

開場

在日常生活中,我們常常需要處理各種待辦事項,無論是讀書計畫、工作安排,還是生活中的小提醒,若能有個工具在適當的時間提醒自己,就能避免遺漏重要的事情。

今天要實作的小程式目標很單純:建立一個簡單的記事提醒工具,讓使用者能輸入事項與提醒時間,並在時間到時自動跳出提示。

那我們馬上開始實作吧!

1.記事提醒程式碼

(1)資料存取(Load / Save)

提醒事項需要能夠「存檔」與「讀檔」,我這裡用 JSON 檔案 reminders.json 來保存,同時也會補上 done 欄位,避免舊資料缺少狀態。

DATA_FILE = "reminders.json"

def load_reminders():
    try:
        with open(DATA_FILE, "r", encoding="utf-8") as f:
            data = json.load(f)
            for r in data:
                if "done" not in r:
                    r["done"] = False
            return data
    except FileNotFoundError:
        return []

def save_reminders():
    with open(DATA_FILE, "w", encoding="utf-8") as f:
        json.dump(reminders, f, ensure_ascii=False, indent=2)

(2)新增 / 編輯 / 刪除提醒

提供使用者新增提醒,並設定日期、時間與重複方式,同時也可以「標記完成」或「刪除」。

  • 新增提醒:將使用者輸入的標題、日期、時間與重複設定,組合成一個提醒物件,再存進 reminders 清單。
def add_reminder():
    title = title_entry.get().strip()
    date = date_entry.get_date()
    hour = hour_var.get()
    minute = minute_var.get()
    repeat = repeat_var.get()

    if not title:
        messagebox.showwarning("警告", "請輸入提醒內容!")
        return

    remind_time = datetime.combine(date, datetime.min.time()).replace(hour=hour, minute=minute)
    reminder = {
        "title": title,
        "time": remind_time.strftime("%Y-%m-%d %H:%M"),
        "repeat": repeat,
        "done": False
    }
    reminders.append(reminder)
    save_reminders()
    refresh_list()
    title_entry.delete(0, tk.END)
  • 標記完成 / 取消完成:點選清單中的提醒,可以切換「完成 / 未完成」狀態。
def toggle_done():
    selected = reminder_list.curselection()
    if not selected:
        return
    index = selected[0]
    reminders[index]["done"] = not reminders[index]["done"]
    save_reminders()
    refresh_list()
  • 刪除提醒:將使用者選中的提醒直接刪除。
def delete_reminder():
    selected = reminder_list.curselection()
    if not selected:
        return
    index = selected[0]
    reminders.pop(index)
    save_reminders()
    refresh_list()

(3)GUI 介面設計

  • 輸入區:包含提醒內容、日期、時間、重複方式,利用 Entry 輸入提醒內容、DateEntry 選日期、Spinbox 選小時分鐘,Combobox 選擇重複方式。
frame_top = ttk.Frame(root, padding=10)
frame_top.pack(fill="x")

ttk.Label(frame_top, text="提醒內容:").grid(row=0, column=0, padx=5, pady=5)
title_entry = ttk.Entry(frame_top, width=25)
title_entry.grid(row=0, column=1, padx=5, pady=5)
ttk.Label(frame_top, text="日期:").grid(row=1, column=0, padx=5, pady=5)
date_entry = DateEntry(frame_top, width=12, background="darkblue",
                       foreground="white", date_pattern="yyyy-mm-dd")
date_entry.grid(row=1, column=1, padx=5, pady=5, sticky="w")
hour_var = tk.IntVar(value=12)
minute_var = tk.IntVar(value=0)
hour_spin = ttk.Spinbox(frame_top, from_=0, to=23, textvariable=hour_var, width=5)
minute_spin = ttk.Spinbox(frame_top, from_=0, to=59, textvariable=minute_var, width=5)
  • 提醒清單區:用 Listbox 顯示所有提醒,右側有 Scrollbar。
frame_mid = ttk.Frame(root, padding=10)
frame_mid.pack(fill="both", expand=True)

reminder_list = tk.Listbox(frame_mid, height=15)
reminder_list.pack(fill="both", expand=True, side="left")

scrollbar = ttk.Scrollbar(frame_mid, orient="vertical", command=reminder_list.yview)
scrollbar.pack(side="right", fill="y")
reminder_list.config(yscrollcommand=scrollbar.set)
  • 底部操作按鈕:操作提醒的功能:完成 / 取消完成、刪除提醒。
frame_bottom = ttk.Frame(root, padding=10)
frame_bottom.pack(fill="x")

done_button = ttk.Button(frame_bottom, text="完成 / 取消完成", command=toggle_done)
done_button.pack(side="left", padx=5)

delete_button = ttk.Button(frame_bottom, text="刪除提醒", command=delete_reminder)
delete_button.pack(side="left", padx=5)

(4)彈窗提醒(Messagebox)

  • 在指定時間點,透過 tkinter 的訊息視窗跳出提醒,不會受到 VS Code 或 IDE 限制。
def show_reminder(title):
    messagebox.showinfo("記事提醒", title)

(5)背景檢查機制

這部分是程式的「心臟」,負責定時檢查是否有提醒需要跳出。

  • 基本檢查流程:每 10 秒檢查一次,把目前時間與提醒時間比對。
def check_reminders():
    while True:
        now = datetime.now().strftime("%Y-%m-%d %H:%M")
        for r in reminders:
            if not r["done"] and r["time"] == now:
                root.after(0, lambda t=r["title"]: show_reminder(t))
  • 重複提醒的處理:若設定「每日 / 每週 / 每月」,就會自動更新下一次的提醒時間;若是「單次」,則標記為完成。
                remind_time = datetime.strptime(r["time"], "%Y-%m-%d %H:%M")
                if r["repeat"] == "每日":
                    remind_time += timedelta(days=1)
                elif r["repeat"] == "每週":
                    remind_time += timedelta(weeks=1)
                elif r["repeat"] == "每月":
                    month = (remind_time.month % 12) + 1
                    year = remind_time.year + (remind_time.month // 12)
                    day = remind_time.day
                    try:
                        remind_time = remind_time.replace(year=year, month=month, day=day)
                    except ValueError:
                        next_month = datetime(year, month + 1, 1)
                        remind_time = next_month - timedelta(days=1)
                else:
                    r["done"] = True

  • 更新狀態與存檔:將更新後的提醒存回 JSON,並刷新 GUI。
                r["time"] = remind_time.strftime("%Y-%m-%d %H:%M")
                save_reminders()
                refresh_list()
        time.sleep(10)  # 每 10 秒檢查一次

主程式啟動

最後,把所有功能串接起來,啟動 GUI 主迴圈,並在背景執行檢查提醒的執行緒。

reminders = load_reminders()
refresh_list()

threading.Thread(target=check_reminders, daemon=True).start()

root.mainloop()

2.記事提醒成果展示

(1)記事提醒為寫作業(單次)

32

(2)警告項目!沒有輸入提醒內容

33

(3)記事提醒為去洗澡(每日)

34

3.心得

在這次記事提醒小程式的開發過程中,從最初的簡單文字提醒,到逐步加入日期選擇、重複提醒與完成狀態等功能,每增加一項功能,成就感都會隨之提升。為了讓小程式更貼近生活使用需求,在不斷嘗試與調整語法的過程中,我逐漸理解到軟體開發的核心,其實就是持續迭代與反覆測試。每一次錯誤訊息的排查,都是對耐心與思考方式的磨練。當最終看到一個能獨立運作的小程式誕生時,那份成就感遠遠超過過程中的挫折!
祝大家也在寫這份小程式時能找到屬於這份對於程式碼的熱情~


上一篇
[Day19]從初級到進階!解鎖 Factory與 Observer模式
系列文
軟體開發養成計畫:以小程式實作深化開發能力20
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言